#include "hk_sht30.hpp"
#include <iomanip>

#ifndef HK_SHT30_USE_CONFIG_H
#define HK_SHT30_NAME ("hk_sht30")

#define HK_SHT30_RS485_PATH ("/dev/ttyUSB0")
#define HK_SHT30_RS485_BAUDRATE (115200)
#define HK_SHT30_RS485_DE_PATH ("/dev/gpiochip3")
#define HK_SHT30_RS485_DE_PIN (24)
#define HK_SHT30_RS485_FRAME_TIMEOUT_MS (500)

#define HK_SHT30_MODBUS_SLAVE_ADDR (0x10)
#endif // !HK_SHT30_USE_CONFIG_H

uart_v2 *Phk_sht30_uart = NULL;
rs485_v3 *Phk_sht30_rs485 = NULL;
agile_modbus_rtu_master_simple *Phk_sht30_rtu_master = NULL;

static yj_return init_flag = YJ_ERROR;

int hk_sht30_rs485_modbus_read(uint8_t *data)
{
    if (!Phk_sht30_rs485 || !Phk_sht30_rtu_master || !Phk_sht30_uart || !data)
        return -1;
    return Phk_sht30_rs485->rs485_recv(data, MAX_ADU_LENGTH);
}

int hk_sht30_rs485_modbus_write(uint8_t *data, uint32_t len)
{
    if (!Phk_sht30_rs485 || !Phk_sht30_rtu_master || !Phk_sht30_uart || !data)
        return -1;
    return Phk_sht30_rs485->rs485_send(data, len);
}

yj_return hk_sht30_init(void)
{
    std::string name(HK_SHT30_NAME);

    extern uart_v2 *Pmyantenna_laser_uart;
    extern rs485_v3 *Pmyantenna_laser_rs485;
    extern agile_modbus_rtu_master_simple *Pmyantenna_laser_rtu_master;
    Phk_sht30_uart = Pmyantenna_laser_uart;
    Phk_sht30_rs485 = Pmyantenna_laser_rs485;
    // Phk_sht30_uart = new uart_v2(HK_SHT30_RS485_PATH, HK_SHT30_RS485_BAUDRATE, 8, 1);
    // Phk_sht30_rs485 = new rs485_v3(Phk_sht30_uart, HK_SHT30_RS485_DE_PATH, HK_SHT30_RS485_DE_PIN, HK_SHT30_RS485_FRAME_TIMEOUT_MS);
    Phk_sht30_rtu_master = new agile_modbus_rtu_master_simple(name,
                                                              hk_sht30_rs485_modbus_write,
                                                              hk_sht30_rs485_modbus_read);

    if (Phk_sht30_rs485->rs485_open() != YJ_OK)
        return init_flag;
    if (Phk_sht30_rtu_master->init() != 0)
        return init_flag;
    init_flag = YJ_OK;
    return init_flag;
}

void hk_sht30_deinit(void)
{
    if (Phk_sht30_rs485)
    {
        Phk_sht30_rs485->rs485_close();
        delete Phk_sht30_rs485;
        Phk_sht30_rs485 = NULL;
    }
    if (Phk_sht30_rtu_master)
    {
        delete Phk_sht30_rtu_master;
        Phk_sht30_rtu_master = NULL;
    }
    if (Phk_sht30_uart)
    {
        delete Phk_sht30_uart;
        Phk_sht30_uart = NULL;
    }
}

yj_return hk_sht30_read_all(hk_sht30_data_t *data)
{
    uint32_t temp1, temp2;
    std::vector<uint16_t> dataTorecv(4);

    if (init_flag == YJ_ERROR || !data)
    {
        LOG(ERROR) << "❌ hk_sht30_read_all init_flag error or data is null";

        return YJ_ERROR;
    }
    std::unique_lock<std::mutex> lock(Phk_sht30_rs485->rs485_get_mutex());
    if (Phk_sht30_rtu_master->read_holding_register_multiple(HK_SHT30_MODBUS_SLAVE_ADDR, 0x02, dataTorecv) < 0)
    {
        LOG(ERROR) << "❌ hk_sht30_read_all read holding regs error";
        return YJ_ERROR;
    }
    lock.unlock();

    temp1 = dataTorecv[1] | (dataTorecv[0] << 16);
    data->temperature = *(float *)((void *)(&temp1)); // ℃
    temp2 = dataTorecv[3] | (dataTorecv[2] << 16);
    data->humidity = *(float *)((void *)(&temp2)); // %RH

    return YJ_OK;
}

void hk_sht30_print_data(hk_sht30_data_t *data)
{
    if (!data)
    {
        LOG(ERROR) << "hk_sht30_print_data data is null";
        return;
    }

    LOG(INFO) << "\n============= data start =============\n"
              << "temperature: " << data->temperature << " ℃\n"
              << "humidity: " << data->humidity << " \%RH\n"
              << "============= data end =============\n";
}